import { ref, computed, readonly } from 'vue'
import { defineStore } from 'pinia'
import type { 
  Message, 
  SendMessageRequest, 
  GetMessagesRequest,
  MarkMessageReadRequest
} from '@/types'
import { messageService } from '@/services/message'
import { chatStorage } from '@/utils/storage'
import { messageCache } from '@/utils/messageCache'
import { handleError, retryOperation } from '@/utils/errorHandler'
import { loadingManager, LoadingKeys } from '@/utils/loadingManager'

export const useMessagesStore = defineStore('messages', () => {
  // State
  const messagesByConversation = ref<Record<string, Message[]>>({})
  const sendingMessages = ref<Record<string, Message>>({})
  const isLoading = ref(false)
  const isLoadingHistory = ref<Record<string, boolean>>({})
  const error = ref<string | null>(null)
  const loadErrors = ref<Record<string, string>>({})
  const hasMoreMessages = ref<Record<string, boolean>>({})
  const retryAttempts = ref<Record<string, number>>({})
  const lastLoadTime = ref<Record<string, number>>({})

  // Getters
  const getMessagesByConversation = computed(() => {
    return (conversationId: string): Message[] => {
      return messagesByConversation.value[conversationId] || []
    }
  })

  const getSendingMessages = computed(() => {
    return Object.values(sendingMessages.value)
  })

  const getUnreadCount = computed(() => {
    return (conversationId: string): number => {
      const messages = messagesByConversation.value[conversationId] || []
      return messages.filter(msg => !msg.isRead).length
    }
  })

  const hasMoreMessagesForConversation = computed(() => {
    return (conversationId: string): boolean => {
      return hasMoreMessages.value[conversationId] ?? true
    }
  })

  const isLoadingHistoryForConversation = computed(() => {
    return (conversationId: string): boolean => {
      return isLoadingHistory.value[conversationId] ?? false
    }
  })

  const getLoadErrorForConversation = computed(() => {
    return (conversationId: string): string | null => {
      return loadErrors.value[conversationId] || null
    }
  })

  const getRetryAttemptsForConversation = computed(() => {
    return (conversationId: string): number => {
      return retryAttempts.value[conversationId] || 0
    }
  })

  // Actions
  const loadMessages = async (request: GetMessagesRequest): Promise<void> => {
    const { conversationId } = request
    const isFirstPage = request.page === 1 || !request.page
    const loadingKey = isFirstPage ? LoadingKeys.LOAD_MESSAGES : LoadingKeys.LOAD_MORE_MESSAGES
    
    try {
      // Start loading state
      loadingManager.start(loadingKey, isFirstPage ? '加载消息中...' : '加载更多消息...')
      
      if (isFirstPage) {
        isLoading.value = true
        // Try to load from cache first for initial load
        const cachedMessages = messageCache.getMessages(conversationId, 50)
        if (cachedMessages.length > 0) {
          messagesByConversation.value[conversationId] = cachedMessages
        }
      } else {
        isLoadingHistory.value[conversationId] = true
      }
      
      error.value = null
      loadErrors.value[conversationId] = ''

      const response = await retryOperation(
        () => messageService.getMessages(
          request.conversationId,
          request.page,
          request.pageSize,
          request.beforeMessageId
        ),
        `load-messages-${conversationId}-${request.page || 1}`
      )
      
      const messages = response.items || []
      
      if (isFirstPage) {
        // First page - replace existing messages
        messagesByConversation.value[conversationId] = messages
        // Cache the messages using message cache manager
        messageCache.addMessages(conversationId, messages)
        chatStorage.setCachedMessages(conversationId, messages)
      } else {
        // Subsequent pages - prepend to existing messages
        const existing = messagesByConversation.value[conversationId] || []
        const newMessages = [...messages, ...existing]
        messagesByConversation.value[conversationId] = newMessages
        // Update cache with new messages
        messageCache.addMessages(conversationId, messages)
        chatStorage.setCachedMessages(conversationId, newMessages)
      }
      
      // Update hasMore flag and pagination state
      hasMoreMessages.value[conversationId] = response.hasNext || false
      lastLoadTime.value[conversationId] = Date.now()
      retryAttempts.value[conversationId] = 0
      
      // Save pagination state
      chatStorage.setPaginationState(conversationId, {
        hasMore: response.hasNext,
        lastMessageId: messages[0]?.messageId,
        totalLoaded: messagesByConversation.value[conversationId].length
      })
      
    } catch (err: any) {
      const errorMessage = err.message || '加载消息失败'
      
      // Handle error with error handler
      handleError(err, {
        action: 'loadMessages',
        conversationId,
        isFirstPage,
        request
      })
      
      if (isFirstPage) {
        error.value = errorMessage
      } else {
        loadErrors.value[conversationId] = errorMessage
      }
      
      // Record failure for retry logic
      chatStorage.setLoadFailure(conversationId, {
        error: errorMessage,
        timestamp: Date.now(),
        request
      })
      
      throw err // Re-throw to allow caller to handle
    } finally {
      // Stop loading state
      loadingManager.stop(loadingKey)
      
      if (isFirstPage) {
        isLoading.value = false
      } else {
        isLoadingHistory.value[conversationId] = false
      }
    }
  }

  const sendMessage = async (request: SendMessageRequest): Promise<Message | null> => {
    // Import connection store dynamically to avoid circular dependency
    const { useConnectionStore } = await import('./connection')
    const connectionStore = useConnectionStore()
    
    const clientMessageId = request.clientMessageId || `temp_${Date.now()}_${Math.random()}`
    
    try {
      // Start loading state
      loadingManager.start(LoadingKeys.SEND_MESSAGE, '发送消息中...')
      
      // Create temporary message for optimistic UI
      const tempMessage: Message = {
        messageId: clientMessageId,
        fromUserId: 0, // Will be set by auth store
        conversationId: request.conversationId,
        messageType: request.messageType,
        content: request.content,
        status: 'SENDING',
        createdAt: new Date(),
        sequence: Date.now(),
        isRead: false,
        senderNickname: '',
        senderAvatarUrl: '',
        replyToMessageId: request.replyToMessageId
      }

      // Add to sending messages
      sendingMessages.value[clientMessageId] = tempMessage
      
      // Add to conversation messages for optimistic UI
      const conversationMessages = messagesByConversation.value[request.conversationId] || []
      messagesByConversation.value[request.conversationId] = [...conversationMessages, tempMessage]

      // Check if connected, if not cache the message for offline sync
      if (!connectionStore.isConnected) {
        console.log('Connection offline, caching message for later sync')
        connectionStore.cacheOfflineMessage(request)
        
        // Update message status to indicate it's cached for offline sync
        tempMessage.status = 'FAILED' // Will be retried when connection is restored
        const messages = messagesByConversation.value[request.conversationId] || []
        const tempIndex = messages.findIndex(msg => msg.messageId === clientMessageId)
        if (tempIndex !== -1) {
          messages[tempIndex] = tempMessage
        }
        
        // Remove from sending messages
        delete sendingMessages.value[clientMessageId]
        
        return tempMessage
      }

      // Send message to server with retry
      const response = await retryOperation(
        () => messageService.sendMessage(
          request.conversationId,
          request.messageType,
          request.content,
          request.replyToMessageId
        ),
        `send-message-${clientMessageId}`
      )
      
      // Remove from sending messages
      delete sendingMessages.value[clientMessageId]
      
      // Replace temp message with real message
      const messages = messagesByConversation.value[request.conversationId] || []
      const tempIndex = messages.findIndex(msg => msg.messageId === clientMessageId)
      
      if (tempIndex !== -1) {
        messages[tempIndex] = response
      } else {
        messages.push(response)
      }
      
      messagesByConversation.value[request.conversationId] = [...messages]
      return response
    } catch (err: any) {
      // Handle error with error handler
      handleError(err, {
        action: 'sendMessage',
        conversationId: request.conversationId,
        messageType: request.messageType,
        clientMessageId
      })
      
      // If sending fails and we're connected, cache for offline sync
      if (connectionStore.isConnected) {
        console.log('Message send failed while connected, caching for retry')
        connectionStore.cacheOfflineMessage(request)
      }
      
      // Update message status to failed
      const messages = messagesByConversation.value[request.conversationId] || []
      const tempIndex = messages.findIndex(msg => msg.messageId === clientMessageId)
      if (tempIndex !== -1) {
        messages[tempIndex].status = 'FAILED'
      }
      
      // Remove from sending messages
      delete sendingMessages.value[clientMessageId]
      
      error.value = err.message || '发送消息时发生错误'
      return null
    } finally {
      // Stop loading state
      loadingManager.stop(LoadingKeys.SEND_MESSAGE)
    }
  }

  const markMessageAsRead = async (request: MarkMessageReadRequest): Promise<void> => {
    try {
      await messageService.markMessageAsRead(request.messageId, request.conversationId)
      
      // Update local message status
      const messages = messagesByConversation.value[request.conversationId] || []
      const messageIndex = messages.findIndex(msg => msg.messageId === request.messageId)
      
      if (messageIndex !== -1) {
        messages[messageIndex].isRead = true
        messages[messageIndex].status = 'READ'
      }
    } catch (err: any) {
      console.error('Mark message as read failed:', err)
    }
  }

  const addMessage = (message: Message): void => {
    const conversationId = message.conversationId
    const messages = messagesByConversation.value[conversationId] || []
    
    // Check if message already exists (deduplication)
    const existingIndex = messages.findIndex(msg => msg.messageId === message.messageId)
    
    if (existingIndex === -1) {
      // Add new message
      const newMessages = [...messages, message]
      
      // Sort by sequence and createdAt to maintain proper order
      newMessages.sort((a, b) => {
        // First sort by sequence number
        if (a.sequence !== b.sequence) {
          return a.sequence - b.sequence
        }
        // If sequence is the same, sort by creation time
        return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
      })
      
      messagesByConversation.value[conversationId] = newMessages
      
      // Add to cache
      messageCache.addMessage(conversationId, message)
    } else {
      // Update existing message (merge with new data)
      const updatedMessage = {
        ...messages[existingIndex],
        ...message,
        // Preserve original creation time if it exists
        createdAt: messages[existingIndex].createdAt || message.createdAt
      }
      
      messages[existingIndex] = updatedMessage
      messagesByConversation.value[conversationId] = [...messages]
      
      // Update in cache
      messageCache.updateMessage(conversationId, message.messageId, updatedMessage)
    }
  }

  const updateMessageStatus = (messageId: string, status: Message['status']): void => {
    // Find and update message across all conversations
    Object.keys(messagesByConversation.value).forEach(conversationId => {
      const messages = messagesByConversation.value[conversationId]
      const messageIndex = messages.findIndex(msg => msg.messageId === messageId)
      
      if (messageIndex !== -1) {
        messages[messageIndex].status = status
        if (status === 'READ') {
          messages[messageIndex].isRead = true
        }
      }
    })
  }

  const retryFailedMessage = async (messageId: string): Promise<void> => {
    // Find the failed message
    let failedMessage: Message | null = null
    let conversationId = ''
    
    for (const convId of Object.keys(messagesByConversation.value)) {
      const messages = messagesByConversation.value[convId]
      const message = messages.find(msg => msg.messageId === messageId && msg.status === 'FAILED')
      if (message) {
        failedMessage = message
        conversationId = convId
        break
      }
    }
    
    if (failedMessage) {
      const request: SendMessageRequest = {
        conversationId,
        messageType: failedMessage.messageType,
        content: failedMessage.content,
        replyToMessageId: failedMessage.replyToMessageId,
        clientMessageId: messageId
      }
      
      await sendMessage(request)
    }
  }

  const clearMessages = (conversationId?: string): void => {
    if (conversationId) {
      delete messagesByConversation.value[conversationId]
      delete hasMoreMessages.value[conversationId]
    } else {
      messagesByConversation.value = {}
      hasMoreMessages.value = {}
    }
  }

  const loadMoreHistory = async (conversationId: string): Promise<void> => {
    if (isLoadingHistory.value[conversationId] || !hasMoreMessages.value[conversationId]) {
      return
    }

    const currentMessages = messagesByConversation.value[conversationId] || []
    const oldestMessage = currentMessages[0]
    
    if (!oldestMessage) {
      return
    }

    const request: GetMessagesRequest = {
      conversationId,
      pageSize: 20,
      beforeMessageId: oldestMessage.messageId
    }

    await loadMessages(request)
  }

  const retryLoadMessages = async (conversationId: string): Promise<void> => {
    const failure = chatStorage.getLoadFailure(conversationId)
    if (!failure || !(failure as any).request) {
      return
    }

    const currentAttempts = retryAttempts.value[conversationId] || 0
    const maxRetries = 3

    if (currentAttempts >= maxRetries) {
      loadErrors.value[conversationId] = '重试次数已达上限，请稍后再试'
      return
    }

    retryAttempts.value[conversationId] = currentAttempts + 1
    
    try {
      await loadMessages((failure as any).request as GetMessagesRequest)
      // Clear failure record on success
      chatStorage.removeLoadFailure(conversationId)
    } catch (err: any) {
      // Keep the failure record for next retry
      console.error('Retry load messages failed:', err)
    }
  }

  const refreshMessages = async (conversationId: string): Promise<void> => {
    // Clear cache and reload from server
    chatStorage.removeCachedMessages(conversationId)
    chatStorage.removePaginationState(conversationId)
    
    const request: GetMessagesRequest = {
      conversationId,
      page: 1,
      pageSize: 20
    }

    await loadMessages(request)
  }

  const preloadMessages = async (conversationId: string): Promise<void> => {
    // Check if messages are already cached and recent
    const lastLoad = lastLoadTime.value[conversationId]
    const cacheExpiry = 5 * 60 * 1000 // 5 minutes
    
    if (lastLoad && Date.now() - lastLoad < cacheExpiry) {
      return
    }

    const cachedMessages = chatStorage.getCachedMessages(conversationId)
    if (cachedMessages.length > 0) {
      messagesByConversation.value[conversationId] = cachedMessages
    }

    // Load fresh data in background
    try {
      const request: GetMessagesRequest = {
        conversationId,
        page: 1,
        pageSize: 20
      }
      await loadMessages(request)
    } catch (err) {
      // Silently fail for preload
      console.warn('Preload messages failed:', err)
    }
  }

  const clearError = (): void => {
    error.value = null
  }

  const clearLoadError = (conversationId: string): void => {
    delete loadErrors.value[conversationId]
    chatStorage.removeLoadFailure(conversationId)
  }

  const clearConversationData = (conversationId: string): void => {
    delete messagesByConversation.value[conversationId]
    delete hasMoreMessages.value[conversationId]
    delete isLoadingHistory.value[conversationId]
    delete loadErrors.value[conversationId]
    delete retryAttempts.value[conversationId]
    delete lastLoadTime.value[conversationId]
    chatStorage.clearConversationCache(conversationId)
  }

  return {
    // State
    messagesByConversation: readonly(messagesByConversation),
    sendingMessages: readonly(sendingMessages),
    isLoading: readonly(isLoading),
    isLoadingHistory: readonly(isLoadingHistory),
    error: readonly(error),
    loadErrors: readonly(loadErrors),
    hasMoreMessages: readonly(hasMoreMessages),
    retryAttempts: readonly(retryAttempts),
    
    // Getters
    getMessagesByConversation,
    getSendingMessages,
    getUnreadCount,
    hasMoreMessagesForConversation,
    isLoadingHistoryForConversation,
    getLoadErrorForConversation,
    getRetryAttemptsForConversation,
    
    // Actions
    loadMessages,
    loadMoreHistory,
    retryLoadMessages,
    refreshMessages,
    preloadMessages,
    sendMessage,
    markMessageAsRead,
    addMessage,
    updateMessageStatus,
    retryFailedMessage,
    clearMessages,
    clearError,
    clearLoadError,
    clearConversationData
  }
})